<?php
/**
 * 事件处理类
 * 
 * @author Jestery <jestery@gmail.com>
 * 
 * 注册事件处理者：
 * 
 * 通过
 * Event::registerEventHandler('Object.EventName', $handlerObject, $handlerMethod)
 * 来注册一个事件处理者。其中第一个参数是用点（.）分割的事件名称，点前是事件发送者的类名称，点
 * 后面是事件名称，不区分大小写。第二个参数是一个已经实例化的包含处理者方法的类。第三个参数是实际
 * 处理该事件的方法。
 * 
 * 事件处理者：
 * 
 * 事件处理方法要接受两个参数。第一个参数是事件的发送者，第二个参数是一个数组形式的
 * 参数列表。其中，数组里面的参数是通过引用传递的，所以可以直接在处理过程中修改参数。
 * 
 * 事件引发者通过
 * Event::notifyEvent($this, 'eventName', array(&$param1, &$param2))
 * 的形式引发事件
 * 
 * 实例：
 * <code>
 * class Car
 * {
 *  	public function turn($direction)
 *  	{
 *  		echo "Turnning $direction ...\n";
 *  		Event::notifyEvent($this, 'onTurn', array('direction'=>&$direction));
 *  		echo "Now I'm driving $direction !";
 *  	}
 *  	public function leftLightOn()
 *  	{
 *  		echo "Left light turned on.\n";
 *  	}
 *  	public function rightLightOn()
 *  	{
 *  		echo "Right light turned on.\n";
 *  	}
 * }
 * 
 * class Event_Handler
 * {
 *  	public function turnHandler($sender, $params)
 *  	{
 *  		if ($params['direction']=='left')
 *  		{
 *  			$sender->leftLightOn();
 *  		}
 *  		else
 *  		{
 *  			$sender->rightLightOn();
 *  		}
 *  		$params['direction'] = 'forward';
 *  	}
 * }
 * 
 * $handler = new Event_Handler();
 * Event::registerEventHandler('Car.onTurn', $handler, 'turnHandler');
 * $car = new Car();
 * $car->turn('left');
 * 
 * // Outputs:
 * // 	Turnning left ...
 * // 	Left light turned on.
 * // 	Now I'm driving forward !
 * </code>
 */
class Event
{
	private static $eventHandlers = array();

	private function __construct(){}

	/**
	 * 注册一个事件处理方法。
	 *
	 * @param string $event		用点（.）分割的事件。点前面是事件发送者，点后面是事件名称，不区分大小写。
	 * 							例如 "Http_Response.preSendBody"和"http_response.presendbody"是一样的。
	 * @param object $object	处理事件的类实例。必须已经实例化。
	 * @param string $method	处理事件的方法的名字。
	 * @return bool
	 */
	public static function registerEventHandler($event, $object, $method)
	{
		list($sender, $event) = explode('.', $event);
		$sender = strtoupper($sender);
		$event = strtoupper($event);
		self::$eventHandlers[$sender][$event]['object'] = $object;
		self::$eventHandlers[$sender][$event]['method'] = $method;
		return true;
	}

	public function notifyEvent($sender, $event, array $params)
	{
		$className = strtoupper(get_class($sender));
		$event = strtoupper($event);
		if (isset(self::$eventHandlers[$className][$event]))
		{
			$handler = array(self::$eventHandlers[$className][$event]['object'],
							 self::$eventHandlers[$className][$event]['method']);
			if (is_callable($handler))
			{
				return call_user_func($handler, $sender, $params);
			}
		}
		return false;
	}
}